﻿using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HtmlParserLib
{
    public class CommonHtmlParser : IHtmlParser
    {
        public event ParsedLinkEventHandler ParsedLink;

        public virtual void ParseUrl(string url)
        {

            //request.OverrideEncoding = Encoding.Default;

                //1.无法侦测在ReponseHeader中无Encoding的
                //var request = new HtmlWeb();
                //request.AutoDetectEncoding = true;
                //HtmlDocument doc = request.Load(url);
                //var uri = request.ResponseUri;

                //可以侦测ReponseHeader中无Encoding，但meta http-equiv="Content-Type"中有charset
            HttpDownloader loader = new HttpDownloader(url, null, null);
            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(loader.GetPage());
            var uri = loader.Url;

            //var linkedPages = doc.DocumentNode.Descendants("a")
            //                      .Select(a => a.GetAttributeValue("href", null))
            //                      .Where(u => !String.IsNullOrEmpty(u));

            var linkedPages = SelectLinkNodes(doc);

            if (ParsedLink != null)
            {
                foreach (var link in linkedPages)
                {
                    var href = link.Attributes["href"].Value;
                    href = GetAbsolueUrl(href, uri);
                    if (!string.IsNullOrEmpty(link.InnerText) && !href.StartsWith("javascript"))
                    {
                        ParsedLink(this, new ParsedLinkEventArgs()
                        {
                            Title = GetLinkTitle(link),
                            Url = href,
                            ResponseUri = uri,
                            OtherInfo = GetOtherInfo(link)
                        });
                    }
                }
            }
        }

        protected virtual string GetOtherInfo(HtmlNode link)
        {
            return "";
        }

        /// <summary>
        /// 获取链接的Title
        /// </summary>
        /// <param name="link"></param>
        /// <returns></returns>
        protected virtual string GetLinkTitle(HtmlNode link)
        {
            var a = link.Attributes["title"];
            if (a != null && !string.IsNullOrEmpty(a.Value))
            {
                return a.Value;
            }
            else
            {
                return link.InnerText;
            }
        }        

        /// <summary>
        /// 选择链接结点
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        protected virtual IEnumerable<HtmlNode> SelectLinkNodes(HtmlDocument doc)
        {
            var linkedPages = doc.DocumentNode.SelectNodes("//a[@href]");
            return linkedPages;
        }

        public object ArgObject
        {
            get;
            set;
        }

        protected virtual string GetAbsolueUrl(string href,Uri responseUri)
        {
            string result = "";

            string fullurl = responseUri.AbsoluteUri;
            var root =responseUri.GetLeftPart(UriPartial.Authority);
            var cur = fullurl.Substring(0, fullurl.LastIndexOf(@"/") + 1);
            if (href.StartsWith(@"/"))
            {
                result = root + href;
            }
            else if (href.StartsWith(@"./"))
            {
                result = cur + href.Substring(2);
            }
            else if (href.StartsWith(@"../"))
            {
                //要判断有多少个../，以找到相应的目录
                var count = href.Split(new string[] { "../" }, StringSplitOptions.None);
                var str = cur.Substring(0, cur.Length - 1);
                for (int i = 0; i < count.Length - 1; i++)
                {
                    str = str.Substring(0, str.LastIndexOf(@"/"));
                }
                result = str + @"/" + count[count.Length - 1];
            }
            else if (href.StartsWith("http") || href.StartsWith("mail") || href.StartsWith("ftp"))
            {
                result = href;
            }
            else
            {
                result = cur + href;
            }
            return result;
        }
    }
}
